#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qtwindow.h"
#include "spellogica.h"

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

QMutex mutexImgPcs;

// assignment list. Shared by mutex.
sList* assignmentlist = NULL;

// camera variables. Shared by mutex.
QImage cameraImage;
void* cameraPixels = NULL;

// speelveld variables. Shared by mutex.
int speelveldIsNew = 0;
QImage speelveldImage;
void* speelveldPixels = NULL;
unsigned int speelveldWidth;
unsigned int speelveldHeight;
unsigned int speelveldStartX;
unsigned int speelveldStartY;
unsigned int speelveldEndX;
unsigned int speelveldEndY;
float speelveldOrientation;

void addAssignment(assignment* a) {
	mutexImgPcs.lock();
		sListAdd(&assignmentlist, (void*)a);
	mutexImgPcs.unlock();
}

void writeCamera(void* pixels, int width, int height) {
	mutexImgPcs.lock();
		if(cameraPixels != NULL) free(cameraPixels);
		cameraPixels = malloc(sizeof(char)*3*width*height);
		memcpy(cameraPixels,pixels,sizeof(char)*3*width*height);
		cameraImage = QImage((const uchar*)cameraPixels,width,height,QImage::Format_RGB888);
	mutexImgPcs.unlock();
}

void writeSpeelveld(
	void* pixels, // pixels is in RGB888 format (24bit/px).
	unsigned int width,
	unsigned int height,
	unsigned int startX,
	unsigned int startY,
	unsigned int endX,
	unsigned int endY
) {
	mutexImgPcs.lock();
		speelveldIsNew = 1;

		// Create a copy of the speelveld itself to later pass to spellogica
		if(speelveldPixels != NULL) free(speelveldPixels); // free if there's one already.
		speelveldPixels = malloc(sizeof(char)*3*width*height);
		memcpy(speelveldPixels,pixels,sizeof(char)*3*width*height);
		speelveldWidth = width;
		speelveldHeight = height;
		speelveldStartX = startX;
		speelveldStartY = startY;
		speelveldEndX = endX;
		speelveldEndY = endY;

		// Create QImage from copied data
		speelveldImage = QImage((const uchar*)speelveldPixels,width,height,QImage::Format_RGB888);
	mutexImgPcs.unlock();
}

void writeOrientation(float orientation) {
	mutexImgPcs.lock();
		speelveldOrientation = orientation;
	mutexImgPcs.unlock();
}

Thread::Thread(){
}
Thread::~Thread(){
}
void Thread::run(){
	cout << "ThImgPcs: start ImgPcs" << endl;
	beeldverwerkingMain();
	cout << "ThImgPcs: exit" << endl;
}

MainWindow::MainWindow(QWidget *parent) :
	QMainWindow(parent),
	ui(new Ui::MainWindow)
{
	cout << "MainW: start application" << endl;    
	assignmentlist = NULL;
	cameraImage = QImage(160,120,QImage::Format_RGB888);
	cameraImage.fill(0);
	cameraPixels = NULL;
	speelveldIsNew = 0;
	speelveldPixels = NULL;
	camConnect = false;
	gameStart = false;
	gamePauze = false;
	speelveldInUse = false;
	ui->setupUi(this);
	ui->tresholdSelect->setValue(128);
	QImage bal("bal.bmp");
	//QImage bal(5,5,QImage::Format_RGB888);
	//bal.fill(0x0000FF00);
	ui->spelBal->setFixedSize(bal.width(),bal.height());
	ui->spelBal->setPixmap(QPixmap::fromImage(bal));
	setBall(bal.bits(), bal.width(), bal.height());

	QImage balRichting(3,3,QImage::Format_RGB888);
	balRichting.fill(0x0000FF00);
	ui->spelBalRichting->setFixedSize(balRichting.width(),balRichting.height());
	ui->spelBalRichting->setPixmap(QPixmap::fromImage(balRichting));

	QImage balVector(3,3,QImage::Format_RGB888);
	balVector.fill(0x000000FF);
	ui->spelBalVector->setFixedSize(balVector.width(),balVector.height());
	ui->spelBalVector->setPixmap(QPixmap::fromImage(balVector));

	QImage startPunt("start.bmp");
	ui->spelStartPunt->setFixedSize(startPunt.width(),startPunt.height());
	ui->spelStartPunt->setPixmap(QPixmap::fromImage(startPunt));

	QImage eindPunt("eind.bmp");
	ui->spelEindPunt->setFixedSize(eindPunt.width(),eindPunt.height());
	ui->spelEindPunt->setPixmap(QPixmap::fromImage(eindPunt));

	timer = new QTimer(this);
	connect(timer, SIGNAL(timeout()), this, SLOT(on_timer()));
	timer->start(15); //Timer interval in ms

	ThImgPcs = new Thread;
	ThImgPcs->start(QThread::HighPriority);

    lblWin.setText(" ");
    ui->statusBar->addPermanentWidget(&lblWin,1);
}
MainWindow::~MainWindow()
{
	cout << "MainW: exit application" << endl;
	if(ThImgPcs->isRunning()){
		cout << "MainW: ThImgPcs is stil running, timeout max; 1000ms" << endl;
		ThImgPcs->wait(1000000); //1000ms
		//if(ThImgPcs->isRunning())
		//	ThImgPcs->terminate();
	}
	free(cameraPixels);
	free(speelveldPixels);
	delete timer;
	delete ui;
}
void MainWindow::closeEvent (QCloseEvent *event)
{
	srand (time(NULL));
	QString msgName;
	if(rand()&1) { // Select randomized name
		msgName = (char*)"Amazing";
	} else {
		msgName = (char*)"Amazeing";
	}
	QMessageBox::StandardButton resBtn = QMessageBox::question( this, msgName,
	                                                            tr("Are you sure?\n"),
	                                                            QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes,
	                                                            QMessageBox::Yes);
	if (resBtn != QMessageBox::Yes) {
		event->ignore();
	}
	else {
		//kill opencv and spellogics.
		assignment* kill = new assignment;
		kill->type = ASSIGNMENT_SHUTDOWN;
		addAssignment(kill);
		cout << "MainW: send shutdown assignment -> ImgPcs" << endl;
		event->accept();
	}
}
void MainWindow::on_tresholdSelect_valueChanged(int arg1)
{
	ui->tresholdSlider->setValue(arg1);
}
void MainWindow::on_tresholdSlider_valueChanged(int value)
{
	ui->tresholdSelect->setValue(value);
	assignment* ThresHold = new assignment;
	ThresHold->type = ASSIGNMENT_CAM_THRESHOLD;
	ThresHold->thresHold = value&0xFF;
	addAssignment(ThresHold);
	cout << "MainW: send threshold assignment -> ImgPcs" << endl;
}
void MainWindow::on_spelStart_clicked()
{
	if(!gameStart){
		assignment* start = new assignment;
		start->type = ASSIGNMENT_CREATE_SPEELVELD;
		addAssignment(start);
		cout << "MainW: send create speelveld assignment -> ImgPcs" << endl;
		speelveldInUse = true;

		QMessageBox::StandardButton resBtn = QMessageBox::question( this, "Amazing",
		                                                            tr("Ready?\n"),
		                                                            QMessageBox::No | QMessageBox::Yes,
		                                                            QMessageBox::Yes);
		if (resBtn == QMessageBox::Yes) {
			ui->spelStart->setText("Stop");
			ui->spelPauze->setText("Pauze");
			gameStart = true;
			gamePauze = false;
		}
		else{
			gameStart = false;
			speelveldInUse = false;
		}
	}
	else{
		ui->spelStart->setText("Play");
		ui->spelPauze->setText("Pauze");
		gameStart = false;
		speelveldInUse = false;
	}
}
void MainWindow::on_spelPauze_clicked()
{
	if(!gamePauze){
		ui->spelPauze->setText("Verder");
		gamePauze = true;
	}
	else{
		ui->spelPauze->setText("Pauze");
		gamePauze = false;
	}
}
void MainWindow::on_camVerbind_clicked()
{
	assignment* cmd = new assignment;
	cmd->type = ASSIGNMENT_CAM_CONNECT_DISCONNECT;

	if(!camConnect){
		ui->camVerbind->setText("Verbreek");
		camConnect = true;
		cmd->camConnect = true;
		cmd->camSelect = ui->cameraSelect->value()&0xFF;
		ui->cameraSelect->setEnabled(false);
	}else{
		ui->camVerbind->setText("Verbind");
		camConnect = false;
		cmd->camConnect = false;
		ui->cameraSelect->setEnabled(true);
	}

	addAssignment(cmd);
}
void MainWindow::on_timer(){
	//cout << "timer tick" << endl;
	mutexImgPcs.lock();
		ui->cameraBeeld->setPixmap(QPixmap::fromImage(cameraImage));
		ui->cameraBeeld->show();
	mutexImgPcs.unlock();
	//cout << "timer tick end" << endl;

	float orientation;
	mutexImgPcs.lock();
	orientation = speelveldOrientation;
	if(speelveldIsNew) {
		ui->spelBeeld->setPixmap(QPixmap::fromImage(speelveldImage));
		setSpeelveld(
			speelveldPixels,
			speelveldWidth,
			speelveldHeight,
			speelveldStartX,
			speelveldStartY,
			speelveldEndX,
			speelveldEndY
		);
		ui->spelStartPunt->setGeometry(QRect(
			speelveldStartX - ui->spelStartPunt->width()/2,
			speelveldStartY - ui->spelStartPunt->height()/2,
			ui->spelStartPunt->width(),
			ui->spelStartPunt->height()
		));
		ui->spelEindPunt->setGeometry(QRect(
			speelveldEndX - ui->spelEindPunt->width()/2,
			speelveldEndY - ui->spelEindPunt->height()/2,
			ui->spelEindPunt->width(),
			ui->spelEindPunt->height()
		));
		speelveldIsNew = 0;
	}
	mutexImgPcs.unlock();

	if(gameStart && !gamePauze) {
		static float drunkmod = 0.0;
		drunkmod += 0.03;
		if(drunkmod > 6.28) drunkmod = 0;
        int status = runSpelLogica(orientation);
        if(status == 1){
            lblWin.setText("Victory!!");
        }
        else if (status == -1){
            lblWin.setText("Error: no gamefield");
        }
        else
        {
            lblWin.setText("");
        }

		int x = getBallX();
		int y = getBallY();
		ui->spelBal->setGeometry(QRect(
			x + ui->spelBeeld->x(),
			y + ui->spelBeeld->y(),
			ui->spelBal->width(),
			ui->spelBal->height()
		));

		int ballCenterX = x + ui->spelBal->width()/2;
		int ballCenterY = y + ui->spelBal->height()/2;

		int moveX = ballCenterX + cos(orientation)*6;
		int moveY = ballCenterY + sin(orientation)*6;
		moveX -= ui->spelBalRichting->width()/2;
		moveY -= ui->spelBalRichting->height()/2;
		ui->spelBalRichting->setGeometry(QRect(
			moveX + ui->spelBeeld->x(),
			moveY + ui->spelBeeld->y(),
			ui->spelBalRichting->width(),
			ui->spelBalRichting->height()
		));

		int vectorX = ballCenterX + getBallVectorX()*4;
		int vectorY = ballCenterY + getBallVectorY()*4;
		vectorX -= ui->spelBalVector->width()/2;
		vectorY -= ui->spelBalVector->height()/2;
		ui->spelBalVector->setGeometry(QRect(
			vectorX + ui->spelBeeld->x(),
			vectorY + ui->spelBeeld->y(),
			ui->spelBalVector->width(),
			ui->spelBalVector->height()
		));
	}
	if(!speelveldInUse && camConnect) {
		assignment* start = new assignment;
		start->type = ASSIGNMENT_CREATE_SPEELVELD;
		addAssignment(start);
	}
	// move QLabel ball to pos x,y
}

assignment* getAssignment(void){
	mutexImgPcs.lock();
		assignment* a = (assignment*) sListFetch(&assignmentlist);
	mutexImgPcs.unlock();

	return a;
}


